/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */package org.merak.core.text.json;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import org.merak.core.text.json.jsonfiers.Jsonfier;

public final class JsonContext {

	//~ Static Attributes ////////////////////////////////////////////////////////
	//****************************************************************************
	private static final Map<Class<?>,TemplateObject> templates      = new HashMap<Class<?>,TemplateObject>(256);
	private static final JsonfierSet                  globalJsonfier = new JsonfierSet();

	//~ Attributes ///////////////////////////////////////////////////////////////
	//****************************************************************************
	private JsonfierSet   localJsonfiers = globalJsonfier;
	private StringBuffer  buffer         = new StringBuffer();
	private Stack<Object> stack          = new Stack<Object>();

	//~ Constructor //////////////////////////////////////////////////////////////
	//****************************************************************************
	/** Should not be instanced by other packages */
	protected JsonContext() {
		// Do nothing here until otherwise stated
	}

	//~ Methods //////////////////////////////////////////////////////////////////
	//****************************************************************************
	public final TemplateObject getTemplate(Object object) {

		synchronized(templates) {
			TemplateObject template = templates.get(object.getClass());
			if (template == null) {
				template = new TemplateObject(object);
				templates.put(object.getClass(), template);
			}
			return template;
		}

	}
	//****************************************************************************
	public final StringBuffer getBuffer() {
		return this.buffer;
	}
	//****************************************************************************
	public final Jsonfier getJsonfier(Object object) {
		return this.localJsonfiers.getJsonfier(object);
	}
	//****************************************************************************
	public final Jsonfier getJsonfier(Class<?> clazz) {
		return this.localJsonfiers.getJsonfier(clazz);
	}
	//****************************************************************************
	public final Jsonfier getJsonfier(Method method) {
		return this.localJsonfiers.getJsonfier(method);
	}
	//****************************************************************************
	public final void render(Object object) throws Exception {
		this.localJsonfiers.getJsonfier(object).render(object, this);
	}
	//****************************************************************************
	public final void render(Object object,JsonfierSet set) throws Exception {

		if (set == null) throw new IllegalArgumentException (
				"JsonfierSet cannot be null"
		);
		JsonfierSet current = this.localJsonfiers;
		this.localJsonfiers = set;
		this.localJsonfiers.getJsonfier(object).render(object, this);
		this.localJsonfiers = current;

	}
	//****************************************************************************
	protected final void stack(Object object) {
		this.stack.push(object);
	}
	//****************************************************************************
	protected final void unstack() {
		this.stack.pop();
	}
	//****************************************************************************
	protected boolean isStacked(Object o) {
		for (Object o2 : this.stack) {
			if ( o2 == o ) return true;
		}
		return false;
	}
	//****************************************************************************
	protected final void clear() {
		this.buffer.setLength(0);
		this.stack.clear();
	}
	//****************************************************************************

}
